Option Strict Off
Option Explicit On
Module ExtractFrames
	'This module separates an avi file into separate frames. It currently works only for motion jpeg files.
	
	'This is a structure to hold the index data at the end of the AVI file it is based on a AVIOLDSTRUCTURE see MSDN website
	Private Structure INDEXSTRUCT
		Dim dwChunkid As Integer 'Holds the idx1 identifier
		Dim dwFlags As Integer 'Various flag data (always is set to decimal 16)
		Dim dwOffset As Integer 'The offset of the data from the start of the file
		Dim dwSize As Integer 'The size of the data chunk
	End Structure
	
	Dim IndexBlock As INDEXSTRUCT 'An instance of the above structure
	
	Dim IndexStartPoint As Integer 'The start point of the index file
	Dim ReadinData1 As Integer 'Data read from the file
	'Dim ReadinData2 As Long                                'Data read from the file
	'Dim ReadinData3 As Long                                'Data read from the file
	Dim MoviStart As Integer 'The byte where the "movi" header is
	Dim idx1Start As Integer 'The byte where th "idx1" index is
	Dim TotNumFrames As Integer 'The total number of frames in the file
	Dim FrameCounter As Integer 'The loop counter that counts through the frames as they are extracted
	Dim JpegFileName As String 'The filename of each new frame
	Dim RawJpegData() As Byte 'A byte array which holds the raw jpeg data taken from the avi file
	Dim FrameText As String 'A string containing frame number 000001, 000002 etc.
	
	Public Function ExtractMultipleFrames(ByRef SourceFileName As String) As Boolean
		ExtractMultipleFrames = False 'Set the funtion to initially return an error
		'UPGRADE_WARNING: Dir has a new behavior. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="9B7D5ADD-D8FE-4819-A36C-6DEDAF088CC7"'
		If Dir(SourceFileName) = "" Then Exit Function 'If the file doesnt exist, exit the function
		On Error Resume Next 'Try to continue if an error occurs
		FileOpen(10, SourceFileName, OpenMode.Binary, OpenAccess.Read) 'Open the avi file for reading
		If GetRefPoints = False Then Exit Function 'Find the start of the movi and index data exit if it doesnt work
		For FrameCounter = 1 To TotNumFrames 'Loop through all the frames
			'UPGRADE_WARNING: Get was upgraded to FileGet and has a new behavior. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="9B7D5ADD-D8FE-4819-A36C-6DEDAF088CC7"'
			FileGet(10, IndexBlock, idx1Start + ((FrameCounter - 1) * 16) + 8 + 1) 'Fill the structure with the frame information
			'  frmUtilities2.List1.AddItem "Frame " & FrameCounter & " starts at &H" & Hex$(IndexBlock.dwOffset) & " and is &H" & Hex$(IndexBlock.dwSize) & " bytes long"
			ReDim RawJpegData(IndexBlock.dwSize - 1) 'Redimension the byte array to be able to hold all the jpg data from image file. This clears it also
			'UPGRADE_WARNING: Get was upgraded to FileGet and has a new behavior. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="9B7D5ADD-D8FE-4819-A36C-6DEDAF088CC7"'
			FileGet(10, RawJpegData, IndexBlock.dwOffset + 8 + 1) 'This pulls the data from the file to fill the data array
			
			If Right(SourceFileName, 4) = ".avi" Then
				SourceFileName = Left(SourceFileName, Int(Len(SourceFileName) - 4))
			End If
			FrameText = LTrim(Str(FrameCounter))
			If Len(FrameText) = 1 Then FrameText = "00000" & FrameText
			If Len(FrameText) = 2 Then FrameText = "0000" & FrameText
			If Len(FrameText) = 3 Then FrameText = "000" & FrameText
			If Len(FrameText) = 4 Then FrameText = "00" & FrameText
			If Len(FrameText) = 5 Then FrameText = "0" & FrameText
			
			JpegFileName = SourceFileName & "_Frame_" & FrameText & ".jpg" 'Generate a new filename
			
			FileOpen(11, JpegFileName, OpenMode.Binary) 'Open a new destination File
			'UPGRADE_WARNING: Put was upgraded to FilePut and has a new behavior. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="9B7D5ADD-D8FE-4819-A36C-6DEDAF088CC7"'
			FilePut(11, RawJpegData) 'Write the raw jpeg data
			FileClose(11) 'Close the file
			frmUtilities2.imgFrameDisplay.Image = System.Drawing.Image.FromFile(JpegFileName) 'Load the picture to the utilities picture window
			frmUtilities2.List1.Items.Add("Frame " & FrameText & " extracted successfully")
			'UPGRADE_ISSUE: ListBox property List1.NewIndex was not upgraded. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="F649E068-7137-45E5-AC20-4D80A3CC70AC"'
            frmUtilities2.List1.SelectedIndex = frmUtilities2.List1.Items.Count - 1 'Scroll listbox down to show last added item
			frmUtilities2.Refresh() 'Refresh the utilities window to show any text output
		Next FrameCounter
		FileClose(10)
		ExtractMultipleFrames = True 'Set the funtion to return a success
	End Function
	Public Function ExtractSingleFrame(ByRef SourceFileName As String, ByRef FrameIDNum As Integer, ByRef DestFileName As String) As Boolean
		ExtractSingleFrame = False 'Set the funtion to initially return an error
		'UPGRADE_WARNING: Dir has a new behavior. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="9B7D5ADD-D8FE-4819-A36C-6DEDAF088CC7"'
		If Dir(SourceFileName) = "" Then Exit Function 'If the file doesnt exist, exit the function
		On Error Resume Next 'Try to continue if an error occurs
		FileOpen(10, SourceFileName, OpenMode.Binary, OpenAccess.Read) 'Open the avi file for reading
		If GetRefPoints = False Then Exit Function 'Find the start of the movi and index data exit if it doesnt work
		If FrameIDNum = -999 Then FrameIDNum = TotNumFrames 'If the program sends -999 then assume that it wants the last frame extracted
		'UPGRADE_WARNING: Get was upgraded to FileGet and has a new behavior. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="9B7D5ADD-D8FE-4819-A36C-6DEDAF088CC7"'
		FileGet(10, IndexBlock, idx1Start + ((FrameIDNum - 1) * 16) + 8 + 1) 'Fill the structure with the frame information of the specified frame
		ReDim RawJpegData(IndexBlock.dwSize - 1) 'Redimension the byte array to be able to hold all the jpg data from image file. This clears it also
		'UPGRADE_WARNING: Get was upgraded to FileGet and has a new behavior. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="9B7D5ADD-D8FE-4819-A36C-6DEDAF088CC7"'
		FileGet(10, RawJpegData, IndexBlock.dwOffset + 8 + 1) 'This pulls the data from the file to fill the data array
		FileOpen(11, DestFileName, OpenMode.Binary) 'Open a new destination File
		'UPGRADE_WARNING: Put was upgraded to FilePut and has a new behavior. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="9B7D5ADD-D8FE-4819-A36C-6DEDAF088CC7"'
		FilePut(11, RawJpegData) 'Write the raw jpeg data
		FileClose(11) 'Close the file
		FileClose(10)
		ExtractSingleFrame = True 'Set the funtion to return a success
	End Function
	Private Function GetRefPoints() As Boolean
		'This subroutine gets vital points in the avi file, such as where the movi data and index start positions are. It returns the points to variables MoviStart and idx1Start
		'It also does some error checking
		GetRefPoints = False 'Initially tell the function to return an error
		'UPGRADE_WARNING: Get was upgraded to FileGet and has a new behavior. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="9B7D5ADD-D8FE-4819-A36C-6DEDAF088CC7"'
		FileGet(10, ReadinData1, 112 + 1) 'Get the data that specifies what type of file we have
		If ReadinData1 = &H47504A4D Then 'Check if data contains "MJPG"
			frmUtilities2.List1.Items.Add("This is a motion jpeg file")
		Else
			Call MsgBox("This doesn't appear to be a Motion Jpeg file" & " but contains " & "&H" & Hex(ReadinData1), MsgBoxStyle.OKOnly + MsgBoxStyle.Exclamation, "Helium Frog Animator")
			Exit Function
		End If
		
		'UPGRADE_WARNING: Get was upgraded to FileGet and has a new behavior. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="9B7D5ADD-D8FE-4819-A36C-6DEDAF088CC7"'
		FileGet(10, ReadinData1, 248 + 1) 'Get the data that specifies the start of the junk header
		If ReadinData1 = &H4B4E554A Then 'Check if data contains "JUNK"
			frmUtilities2.List1.Items.Add("The junk header starts at byte &Hf8")
		Else
			Call MsgBox("I cannot find the Junk Header but found hex value " & "&H" & Hex(ReadinData1), MsgBoxStyle.OKOnly + MsgBoxStyle.Exclamation, "Helium Frog Animator")
			Exit Function
		End If
		
		'UPGRADE_WARNING: Get was upgraded to FileGet and has a new behavior. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="9B7D5ADD-D8FE-4819-A36C-6DEDAF088CC7"'
		FileGet(10, ReadinData1, 252 + 1) 'Get the length of the junk header
		MoviStart = 264 + ReadinData1 'Calculate where "movi" line should be
		'UPGRADE_WARNING: Get was upgraded to FileGet and has a new behavior. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="9B7D5ADD-D8FE-4819-A36C-6DEDAF088CC7"'
		FileGet(10, ReadinData1, MoviStart + 1) 'Extract data from that line
		If ReadinData1 = &H69766F6D Then 'Check if data contains "movi"
			frmUtilities2.List1.Items.Add("The movi header starts at byte " & "&H" & Hex(MoviStart))
		Else
			Call MsgBox("I cannot find the movi header but found hex value " & "&H" & Hex(ReadinData1), MsgBoxStyle.OKOnly + MsgBoxStyle.Exclamation, "Helium Frog Animator")
			Exit Function
		End If
		
		'UPGRADE_WARNING: Get was upgraded to FileGet and has a new behavior. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="9B7D5ADD-D8FE-4819-A36C-6DEDAF088CC7"'
		FileGet(10, ReadinData1, MoviStart - 4 + 1) 'Get the length of the movi data
		idx1Start = MoviStart + ReadinData1 'Calculate where "idx1" line should be
		'UPGRADE_WARNING: Get was upgraded to FileGet and has a new behavior. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="9B7D5ADD-D8FE-4819-A36C-6DEDAF088CC7"'
		FileGet(10, ReadinData1, idx1Start + 1) 'Extract data from that line
		If ReadinData1 = &H31786469 Then 'Check if data contains "idx1"
			frmUtilities2.List1.Items.Add("The idx1 header starts at byte " & "&H" & Hex(idx1Start))
		Else
			Call MsgBox("I cannot find the idx1 header but found hex value " & "&H" & Hex(ReadinData1), MsgBoxStyle.OKOnly + MsgBoxStyle.Exclamation, "Helium Frog Animator")
			Exit Function
		End If
		
		'UPGRADE_WARNING: Get was upgraded to FileGet and has a new behavior. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="9B7D5ADD-D8FE-4819-A36C-6DEDAF088CC7"'
		FileGet(10, TotNumFrames, 48 + 1) 'Get the total number of frames as specified in the header
		'UPGRADE_WARNING: Get was upgraded to FileGet and has a new behavior. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="9B7D5ADD-D8FE-4819-A36C-6DEDAF088CC7"'
		FileGet(10, ReadinData1, idx1Start + 4 + 1) 'get the length of the index in bytes
		If TotNumFrames = ReadinData1 / 16 Then 'The each frame in the index occupies 16 bytes, so check it is the correct length
			frmUtilities2.List1.Items.Add("There are a total of " & TotNumFrames & " frames in the file")
		Else
			Call MsgBox("The index length does not appear to match the number of frames in the header!" & Chr(13) & Chr(10) & "Header says " & TotNumFrames & Chr(13) & Chr(10) & "Index has " & ReadinData1 / 16, MsgBoxStyle.OKOnly + MsgBoxStyle.Exclamation, "Helium Frog Animator")
			Exit Function
		End If
		GetRefPoints = True 'All is Ok so tell main program
	End Function
End Module